package it.ap.sa.core.util;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtilsBean2;
import org.apache.commons.beanutils.PropertyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.vividsolutions.jts.geom.Geometry;

/**
 * Converte tutte le proprietà di un oggetto in proprietà di una feature. 
 * La prop geometryProp specifica la proprietà di tipo geometry da impostare come geometria della feature. 
 * Se il valore della prop non e' di tipo {@link Geometry}, si imposta a null, Al momento non si gestiscono geometrie miste.
 * 
 * @author
 * 
 * @param <T>
 */
public class SimpleFeatureConverter<T> implements FeatureConverter<T> {

	private static final Logger log = LoggerFactory.getLogger(SimpleFeatureConverter.class);
	
	private String geometryProp;
	private HashSet<String> escludeProps = new HashSet<String>();
	private HashSet<String> includeProps = new HashSet<String>();


	public SimpleFeatureConverter(String geometryProp) {
		super();
		this.geometryProp = geometryProp;
	}

	public void includeProp(String name) {
		includeProps.add(name);
	}

	public void excludeProp(String name) {
		escludeProps.add(name);
	}

	private Geometry getGeometry(T t) {
		Geometry ret = null;
		Object o;
		try {
			o = BeanUtilsBean2.getInstance().getPropertyUtils().getProperty(t, geometryProp);
			if (o instanceof Geometry) {
				ret = (Geometry) o;
			}
		} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
			e.printStackTrace();
			log.warn("prop " + geometryProp + " is not a Geometry", e);
		}
		return ret;
	}

	@Override
	public Feature encode(T t) throws Exception {
		@SuppressWarnings("unchecked")
		Map<String, Object> map = PropertyUtils.describe(t);
		// remove class prop
		map.remove("class");
		Feature f = new Feature();
		map.keySet().removeAll(escludeProps);

		if (includeProps.size() > 0) {
			Map<String, Object> tmp = new HashMap<String, Object>();
			for (String key : includeProps) {
				tmp.put(key, map.get(key));
			}
			map.clear();
			map = tmp;
		}
		if (geometryProp != null && map.containsKey(geometryProp)) {
			map.remove(geometryProp);
			f.setGeometry(getGeometry(t));
		}
		f.setProperties(map);

		return f;
	}

	@Override
	public T decode(Feature f) {
		throw new RuntimeException("not impleemnted yet");
	}
}
